package com.itbaizhan.openhis.controller.system;

import cn.hutool.core.date.DateUtil;
import com.itbaizhan.openhis.aspectj.Log;
import com.itbaizhan.openhis.aspectj.enums.BusinessType;
import com.itbaizhan.openhis.constant.Constants;
import com.itbaizhan.openhis.constant.HttpStatus;
import com.itbaizhan.openhis.domain.LoginInfo;
import com.itbaizhan.openhis.domain.Menu;
import com.itbaizhan.openhis.dto.LoginBodyDto;
import com.itbaizhan.openhis.service.LoginInfoService;
import com.itbaizhan.openhis.service.MenuService;
import com.itbaizhan.openhis.utils.AddressUtils;
import com.itbaizhan.openhis.utils.IpUtils;
import com.itbaizhan.openhis.utils.ShiroSecurityUtils;
import com.itbaizhan.openhis.vo.ActiverUser;
import com.itbaizhan.openhis.vo.AjaxResult;
import com.itbaizhan.openhis.vo.MenuTreeVo;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@RestController
@Slf4j
public class LoginController {
    //用于查看用户权限，要先查看菜单
    @Autowired
    private MenuService menuService;

    //用于记录登录日志
    @Autowired
    private LoginInfoService loginInfoService;

    //@Validated 在controller上声明需要对数据进行校验
    @PostMapping("login/doLogin")
    //加了这自定义的横切注解，登录时能把日志自动注入operLog表
    @Log(title = "用户登录",businessType = BusinessType.INSERT)
    public AjaxResult login(@RequestBody @Validated LoginBodyDto loginBodyDto, HttpServletRequest request){
        AjaxResult ajaxResult = AjaxResult.success();
        String password = loginBodyDto.getPassword();
        String username = loginBodyDto.getUsername();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject(); //SecurityUtil 工具类
        //封装loginInfo对象
       LoginInfo loginInfo = createLoginInfo(request);
       loginInfo.setLoginAccount(loginBodyDto.getUsername());

        try {
            subject.login(token);
            //得到会话的token==也就是redis里面存的
            Serializable webToken = subject.getSession().getId();
            ajaxResult.put(Constants.TOKEN, webToken);
            //登录成功的日志
            loginInfo.setMsg("登录成为");
            loginInfo.setLoginStatus(Constants.LOGIN_SUCCESS);
            //当前的登录用户
            loginInfo.setUserName(ShiroSecurityUtils.getCurrentSimpleUser().getUserName());
        }catch (AuthenticationException e){
            log.error("用户名或密码不正确");
            ajaxResult =AjaxResult.error(HttpStatus.ERROR,"用户名或密码不正确");
            //登录失败的日志
            loginInfo.setMsg("用户名或者密码错误");
            loginInfo.setLoginStatus(Constants.LOGIN_ERROR);
        }
        //保存登录信息到数据库
        loginInfoService.insertLoginInfo(loginInfo);
        return ajaxResult;   //将数据返回前端
    }

    //创建登录对象
    /*<!--浏览器解析客户端操作系统、浏览器等-->
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
        </dependency>
        通过这依赖解释浏览器，
        */
    private LoginInfo createLoginInfo(HttpServletRequest request) {
        LoginInfo loginInfo = new LoginInfo();
        //解释浏览器的请求头获得信息
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        //获取ip
        String ipAddr = IpUtils.getIpAddr(request);
        //获取操作系统
        String osName = userAgent.getOperatingSystem().getName();
        //浏览器类型
        String browser = userAgent.getBrowser().getName();
        //获取登录地址
        String location = AddressUtils.getRealAddressByIP(ipAddr);

        loginInfo.setIpAddr(ipAddr);
        loginInfo.setLoginLocation(location);
        loginInfo.setOs(osName);
        loginInfo.setBrowser(browser);
        loginInfo.setLoginTime(DateUtil.date());
        loginInfo.setLoginType(Constants.LOGIN_TYPE_SYSTEM);
        return loginInfo;
    }

    //登录后，获取用户信息
    @GetMapping("login/getInfo")
    public AjaxResult getInfo(){
        Subject subject = SecurityUtils.getSubject();
        ActiverUser activerUser =(ActiverUser) subject.getPrincipal();
        AjaxResult ajaxResult =  AjaxResult.success();
        ajaxResult.put("username",activerUser.getUser().getUserName());
        ajaxResult.put("picture",activerUser.getUser().getPicture());
        ajaxResult.put("roles",activerUser.getRoles()); //角色
        ajaxResult.put("permissions",activerUser.getPermissions());//权限
        return ajaxResult;

    }

    //获取菜单信息
    @GetMapping("login/getMenu")
    public AjaxResult getMenu(){
        Subject subject = SecurityUtils.getSubject();
        ActiverUser activerUser = (ActiverUser)subject.getPrincipal();
        //判断从用户对象获得的用户类型是否admin(管理员)
        boolean isAdmin = activerUser.getUser().getUserType().equals(Constants.USER_ADMIN);
        List<Menu> menus = menuService.selectMenuTree(isAdmin);
        ArrayList<MenuTreeVo> menuVos = new ArrayList<>();
        for(Menu menu : menus){
            menuVos.add(new MenuTreeVo(menu.getMenuId().toString(),menu.getPath(),true));
        }
        return AjaxResult.success(menuVos);
    }


    //退出登录
    @GetMapping("login/loginOut")
    public AjaxResult logOut(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return AjaxResult.success("用户退出成功");
    }

}
